package db.swing2;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.net.URL;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.LinkedHashSet;
import java.util.List;

import javax.swing.JOptionPane;
import javax.swing.event.HyperlinkEvent;
import javax.swing.event.HyperlinkListener;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.MutableTreeNode;
import javax.swing.tree.TreePath;

import de.dnb.basics.applicationComponents.Pair;
import de.dnb.gnd.parser.Record;
import de.dnb.gnd.utils.RecordUtils;

public class Controller {

	private GUI gui;

	private View view;

	private DBConnection dbConnection;

	/**
	 * Setzt zu einem angeklickten Begriff in der Baumdarstellung den
	 * zugehörigen Datensatz in das rechte Fenster (über Portal).
	 * 
	 * @author baumann
	 * 
	 */
	public class OBUBTreeSelectionListener implements TreeSelectionListener {

		@Override
		public void valueChanged(final TreeSelectionEvent event) {
			final TreePath treePath = event.getPath();
			final Object pathComponent = treePath.getLastPathComponent();
			if (!(pathComponent instanceof OBUBTreeNode))
				return;
			OBUBTreeNode treeNode = (OBUBTreeNode) pathComponent;
			final String idn = treeNode.idn;
			getRecordAndPutInTextArea(idn);
		}

	}

	/**
	 * @param idn
	 */
	protected void getRecordAndPutInTextArea(final String idn) {
		view.setStatus("Lade Datensatz ..");
		Thread thread = new Thread() {
			public void run() {
				Record record = RecordUtils.readFromPortal(idn);
				view.setRecord(record);
				view.setStatus("");
			};
		};
		thread.start();
	}

	public class MyWindowClosingListener extends WindowAdapter {
		@Override
		public void windowClosing(final WindowEvent event) {
			dbConnection.close();
			view.close();
		}
	}

	public class MyHitListSelectionListener implements ListSelectionListener {
		@Override
		public void valueChanged(final ListSelectionEvent e) {
			// sonst werden für jeden Klick 2 Events erzeugt:
			if (e.getValueIsAdjusting()) {
				return;
			}
			final int selectedRow = view.getSelectedHitListRow();
			if (selectedRow >= 0) {
				Thread thread = new Thread() {
					@Override
					public void run() {
						view.setStatus("Lade Baumdarstellung ..");
						HitListTableModel model = view.getHitListTableModel();
						Pair<String, String> pair = model
								.getIDandNAmeForSelectedRow(selectedRow);
						String idn = pair.first;
						String name = pair.second;
						OBUBTreeNode node = createTreeForIDAndName(idn, name);
						view.setTree(node);
						getRecordAndPutInTextArea(idn);
						view.setStatus("");
					}
				};
				thread.start();
			}
		}

		/**
		 * Gibt einer idn die Baumstruktur der Unterbegriffe.
		 * 
		 * @param id
		 *            beliebig
		 * @param name
		 *            beliebig
		 * @return einen Baum der UBB oder einen leeren Knoten
		 */
		public OBUBTreeNode createTreeForIDAndName(final String id,
				final String name) {
			if (name == null || name.isEmpty() || id == null || id.isEmpty())
				return null;
			// new DefaultMutableTreeNode("");
			path.clear();
			path.add(id);
			return makeSubTree(id, name);
		}

		/**
		 * Pfad der von der Wurzel bis zum aktuellen Knoten reicht (idn-Liste).
		 */
		private LinkedHashSet<String> path = new LinkedHashSet<String>();

		private OBUBTreeNode makeSubTree(final String id, final String name) {
			final OBUBTreeNode node = new OBUBTreeNode(id, name);
			List<Pair<String, String>> pairs = dbConnection.getUBB(id);
			int index = 0;
			for (Pair<String, String> pair : pairs) {
				String ubID = pair.first;
				String ubName = pair.second;
				if (ubName == null || ubName.isEmpty()) // Abbruch
					continue;
				if (path.contains(ubID)) {
					reportCycle(ubID);
				} else {
					path.add(ubID);
					node.insert(makeSubTree(pair.first, pair.second), index);
					index++;
					path.remove(ubID);
				}
			}
			return node;
		}

		/**
		 * @param ubID
		 *            id des Datensatzes, bei dem der Zyklus endet
		 */
		protected void reportCycle(final String ubID) {
			String s = "Zyklus erkannt: ";
			boolean print = false;
			for (String idPath : path) {
				if (idPath.equals(ubID))
					print = true;
				if (print)
					s += idPath + " - ";
			}
			s += ubID;
			view.addError(s);
		}
	}

	public class SearchIDActionListener implements ActionListener {
		@Override
		public void actionPerformed(ActionEvent e) {
			String id = view.getSearchIDN();
			ResultSet resultSet = dbConnection.getResultsetForID(id);
			HitListTableModel model;
			try {
				model = new HitListTableModel(resultSet);
			} catch (SQLException e1) {
				model = null;
			}
			view.setHitListModel(model);
		}

	}

	public class SearchNameActionListener implements ActionListener,
			KeyListener {
		@Override
		public void actionPerformed(ActionEvent e) {
			doAction();
		}

		protected void doAction() {
			view.setStatus("    suche ...");
			Thread thread = new Thread() {
				@Override
				public void run() {
					String name = view.getSearchTerm();
					String type = view.getSelectedRadioButton();
					HitListTableModel model;
					ResultSet resultSet;
					if (type.length() > 1) {
						resultSet = dbConnection.getResultSetForName(name);
					} else {
						resultSet = dbConnection.getResultSetForNameAndType(
								name, type.charAt(0));
					}
					try {
						model = new HitListTableModel(resultSet);
					} catch (SQLException e) {
						model = null;
					}
					view.setHitListModel(model);
					view.setStatus("");
				}
			};
			thread.start();
		}

		@Override
		public void keyPressed(KeyEvent e) {
		}

		@Override
		public void keyReleased(KeyEvent e) {
			doAction();
		}

		@Override
		public void keyTyped(KeyEvent e) {
		}
	}

	private final class MyHyperlinkListener implements HyperlinkListener {
		public void hyperlinkUpdate(HyperlinkEvent e) {
			if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
				URL url = e.getURL();
				if (url == null)
					return;
				String id = url.getAuthority();
				if (id == null)
					return;
				ResultSet resultSet = dbConnection.getResultsetForID(id);
				HitListTableModel model;
				try {
					model = new HitListTableModel(resultSet);
				} catch (SQLException e1) {
					model = null;
				}
				view.setHitListModel(model);
				getRecordAndPutInTextArea(id);
			}
		}
	}

	public Controller() {
		view = new View();
		view.setTreeSelectionListener(new OBUBTreeSelectionListener());
		try {
			dbConnection = new DBConnection();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		view.setStatus(""); // Zu Beginn: Initialisiere ...
		view.addWindowClosingListener(new MyWindowClosingListener());
		view.setHitListSelectionListener(new MyHitListSelectionListener());
		view.setSearchIDActionListener(new SearchIDActionListener());
		view.setSearchNameActionListener(new SearchNameActionListener());
		view.setLinkListener(new MyHyperlinkListener());
	}

	/**
	 * Launch the application.
	 */
	public static void main(String[] args) {
		new Controller();
	}

}
